﻿/*
 * @Author: ws.s 
 * @Date: 2021-11-25 15:48:18 
 * @Last Modified by:   ws.s 
 * @Last Modified time: 2021-11-25 15:48:18 
 */
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;


/// <summary>
/// 六边形阵列组件，可以按六边形阵列来布局对象
/// </summary>
[ExecuteInEditMode]
public class BhvHexLayout : MonoBehaviour
{
    public int width = 3;

    public float innerRadius = 2f;
    public float outerRadius = 1.5f;

    public int boardRadius = 2;

    public static List<Vector2> hexTiles = new List<Vector2>();

    private float _cellSize = 1f;
    private Vector2[] _posArr = new Vector2[] { };


#if UNITY_EDITOR

    private void OnValidate()
    {
        _dirty = true;
    }
    private bool _dirty = false;

    private void Update()
    {
        if (_dirty == true)
        {
            _dirty = false;
            this.UpdateLayout();
        }
    }
#endif

    private void OnDrawGizmosSelected()
    {
        GizmosExtension.DrawCircle(this.transform.position, Vector3.forward, Color.white, this.width);
        foreach (Transform item in this.transform)
        {
            if (item.gameObject.activeInHierarchy)
            {
                GizmosExtension.DrawCircle(item.transform.position, Vector3.forward, Color.white, this._cellSize);
            }
        }
    }

    public static int GetHexLayoutWidth(int childCount)
    {
        int width = 0;
        int count = childCount;
        while (count > 0)
        {
            if (width == 0)
            {
                count--;
            }
            else
            {
                count -= width * 6;
            }
            width++;
        }
        return width;
    }

    /// <summary>
    /// 根据 ChildCount 获取HexLayout 的坐标
    /// </summary>
    /// <param name="childCount"></param>
    /// <param name="innerRadius"></param>
    /// <param name="cellPosArr"></param>
    /// <param name="cellSize"></param>
    public static void GetHexLayoutPositions(int childCount, float innerRadius, out Vector2[] cellPosArr, out float cellSize)
    {
        GetHexLayoutPositions(GetHexLayoutWidth(childCount), innerRadius * 2f, innerRadius, true, out cellPosArr, out cellSize);
    }

    /// <summary>
    /// 根据棋盘 Radius 获取HexLayout 的坐标
    /// </summary>
    /// <param name="boardRadius"></param>
    /// <param name="width"></param>
    /// <param name="innerRadius"></param>
    /// <param name="sortTop"></param>
    /// <param name="cellPosArr"></param>
    /// <param name="cellSize"></param>
    public static void GetHexLayoutPositions(int boardRadius, float width, float innerRadius, bool sortTop, out Vector2[] cellPosArr, out float cellSize)
    {

        hexTiles.Clear();
        // Vertex radius is minimum out of width/height ratio.
        float vertexRadiusOne = (width) / (3 * innerRadius - 1);
        float vertexRadiusTwo = (width) / (4 * innerRadius - 2) * 2 / Mathf.Sqrt(3);
        float vertexRadius = Mathf.Min(vertexRadiusOne, vertexRadiusTwo);
        // Side radius is based on vertex radius.
        float sideRadius = Mathf.Sqrt(3) * vertexRadius / 2;

        // Board dimensions are based on side and vertex radii.
        var boardHeight = sideRadius * (4 * boardRadius - 2) + 4;
        var boardWidth = vertexRadius * (3 * boardRadius - 1) + 4;

        // First tile in the center.
        // hexTiles.Add(new Vector2(boardWidth / 2, boardHeight / 2));
        hexTiles.Add(new Vector2(0, 0));

        // Rest of the tiles in rings.
        for (var ringI = 1; ringI < boardRadius; ringI++)
        {
            for (var cardinalHexI = 1; cardinalHexI <= 6; cardinalHexI++)
            {
                var xCenter = (0) + sideRadius * (2 * ringI) * Mathf.Cos((2 * Mathf.PI / 6) * cardinalHexI + (Mathf.PI / 6));
                var yCenter = (0) + sideRadius * (2 * ringI) * Mathf.Sin((2 * Mathf.PI / 6) * cardinalHexI + (Mathf.PI / 6));
                hexTiles.Add(new Vector2(xCenter, yCenter));

                var webHexCount = ringI - 1;
                if (webHexCount < 0)
                {
                    webHexCount = 0;
                }

                for (var webHexI = 1; webHexI <= webHexCount; webHexI++)
                {
                    float webHexXCenter = xCenter + (sideRadius * 2 * Mathf.Cos((2 * Mathf.PI / 6) * (2 + cardinalHexI) + (Mathf.PI / 6))) * webHexI;
                    float webHexYCenter = yCenter + (sideRadius * 2 * Mathf.Sin((2 * Mathf.PI / 6) * (2 + cardinalHexI) + (Mathf.PI / 6))) * webHexI;

                    hexTiles.Add(new Vector2(webHexXCenter, webHexYCenter));
                }
            }
        }

        if (sortTop)
        {
            //根据XY排序
            hexTiles.Sort((a, b) => (a.y * -100 + Mathf.Abs(a.x)).CompareTo(b.y * -100 + Mathf.Abs(a.x)));
        }

        cellPosArr = hexTiles.ToArray();
        cellSize = sideRadius;
    }

    // Update is called once per frame
    void UpdateLayout()
    {
        GetHexLayoutPositions(this.boardRadius, this.width, this.innerRadius, true, out this._posArr, out this._cellSize);

        foreach (Transform child in this.transform)
        {
            if (child.GetSiblingIndex() < this._posArr.Length)
            {
                child.gameObject.SetActive(true);
                var pos = this._posArr[child.GetSiblingIndex()];
                child.transform.localPosition = new Vector3(pos.x, 0, pos.y);
            }
            else
            {
                child.gameObject.SetActive(false);
            }
        }

    }

}
